package registeringSystem;

import com.google.appengine.api.datastore.Key;
//import com.google.appengine.api.users.User;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import java.util.Calendar;
import java.util.ArrayList;
import java.util.Collections;

import javax.jdo.PersistenceManager;

@PersistenceCapable
public class OdinsFistSystem 
{
	// need to add persistent tags
	@Persistent
	private ArrayList<User> userHolder;
	@Persistent
	private ArrayList<Course> courseHolder;
	private int lastGeneratedCourseID;
	private int lastGeneratedStudentID;
	private MonthDayYear finalDayToDrop;
	private MonthDayYear finalDayToAdd;
	private MonthDayYear currentDate;

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key theKey;

	// TRY TO FIGURE OUT THE HOW TO MAKE THESE FIELDS STATIC, only one copy
	@Persistent
	private static final int MAX_NUMBER_OF_CREDITS_PER_SEMESTER = 20;

	@Persistent
	private static final int STUDENT_PERMISSION_LEVEL = 0;

	@Persistent
	private static final int TEACHER_PERMISSION_LEVEL = 1;

	@Persistent
	private static final int SCHOOL_ADMINISTRATOR_PERMISSION_LEVEL = 2;

	@Persistent
	private static final int IT_ADMINISTRATOR_PERMISSION_LEVEL = 3;

	@Persistent
	private static int MAX_NUMBER_OF_WAIT_LIST_SPOTS_FOR_A_COURSE = 10;




	public OdinsFistSystem()
	{
		courseHolder = new ArrayList<Course>();
		userHolder = new ArrayList<User>();
		lastGeneratedCourseID = 0;
		lastGeneratedStudentID = 0;
		finalDayToAdd = new MonthDayYear();
		finalDayToDrop = new MonthDayYear();
		currentDate = new MonthDayYear();
		updateCurrentDate();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(courseHolder);
		pm.makePersistent(userHolder);

	} // end of default constructor



	/** 
	 * Name: getTheKey <br><br>
	 * An accessor method that retrieves the the key for the object in the
	 * Google datastore.
	 * <br><br>
	 * Precondition: None <br>
	 * Postcondition: Returns the key. <br>
	 * @param None
	 */
	public Key getTheKey()
	{
		return theKey;
	} // end of getTheKey()

	// need to constant call this method
	private void updateCurrentDate()
	{
		// retrieves the current time
		Calendar today = Calendar.getInstance();

		int month = today.get(Calendar.MONTH);
		int day = today.get(Calendar.DAY_OF_MONTH);
		int year = today.get(Calendar.YEAR);

		try
		{
			currentDate.setAllThreeFields(month, day, year);
		}

		catch(NotValidArgumentException nvae)
		{
			; // do nothing, should not make it in this catch block
		}
	}

	
	public ArrayList<Course> filterCourseNames(String input){
		String input2 = input.toLowerCase();
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getCourseName().toLowerCase().contains(input2))
				filtered.add(c);
		}
		return filtered;
	}	

	public ArrayList<Course> filterCourseTeachers(String input){
		String input2 = input.toLowerCase();
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getInstructorName().toLowerCase().contains(input2))
				filtered.add(c);
		}
		return filtered;
	}		

	public ArrayList<Course> filterCourseLocations(String input){
		String input2 = input.toLowerCase();
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getTeachingLocation().toString().toLowerCase().contains(input2))
				filtered.add(c);
		}
		return filtered;
	}		

	public ArrayList<Course> filterOpenCourses(){
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.isThereOpenSpotsLeftForTheClass())
				filtered.add(c);
		}
		return filtered;
	}	

	public ArrayList<Course> filterCourseDays(String input){
		String input2 = input.toLowerCase();
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getDaysHeld().toLowerCase().contains(input2))
				filtered.add(c);
		}
		return filtered;
	}	

	public ArrayList<Course> filterCourseTimes(String input){
		String input2 = input.toLowerCase();
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getTimeHeld().toString().toLowerCase().contains(input2))
				filtered.add(c);
		}
		return filtered;
	}	

	public ArrayList<Course> filterCourseCapacity(String input){
		int input2 = Integer.parseInt(input);
		ArrayList<Course> filtered = new ArrayList<Course>();
		for(Course c: courseHolder){	
			if(c.getCapacity()==(input2));
			filtered.add(c);
		}
		return filtered;
	}	

	public boolean checkIfTheEnteredPasswordIsValid(User theUser, String thePassword)
	{
		boolean wasThePasswordValid = false;

		if(theUser != null && thePassword != null)
			if(theUser.getPassword().compareTo(thePassword) == 0)
				wasThePasswordValid = true;

		return wasThePasswordValid;
	}


	// move to the system class because there is no access to the data
	public void calculateGPA(User calculateGPAForThisUser) throws NotValidArgumentException  // could return double
	{
		int sum = 0;
		int totalQualityPoints = 0;        // SHOULD BE NUMBER OF CREDIT HOURS
		//char gradeEarned = ' ';


		for(CoursePlusCharacter theCourse: 
			calculateGPAForThisUser.getCompletedCourses())
		{
			// LDLDLDLDLDLDLDLLDLDLDLDL
			System.out.println("GRADE EARNED: " + theCourse.getTheChar());

			switch(theCourse.getTheChar())
			{
			case 'A':
				sum += theCourse.getTheCourse().getNumberOfCredits();
				totalQualityPoints += 
					4 * theCourse.getTheCourse().getNumberOfCredits();
				break;

			case 'B':
				sum += theCourse.getTheCourse().getNumberOfCredits();
				totalQualityPoints += 
					3 * theCourse.getTheCourse().getNumberOfCredits();
				break;

			case 'C':
				sum += theCourse.getTheCourse().getNumberOfCredits();
				totalQualityPoints += 
					2 * theCourse.getTheCourse().getNumberOfCredits();
				break;

			case 'D':
				sum += theCourse.getTheCourse().getNumberOfCredits();
				totalQualityPoints += 
					theCourse.getTheCourse().getNumberOfCredits();
				break;

			case 'F':
				totalQualityPoints += 
					4 * theCourse.getTheCourse().getNumberOfCredits();
				break;
			} // end of switch statement
		} // end of for statement

		// on a 4.0 scale
		double newGPA = (double)totalQualityPoints / sum;

		// LDLDLDLDLDLDLDLDLLDLDLDLDLDLDLDL
		System.out.println(calculateGPAForThisUser.getCompletedCourses());
		System.out.println("SUM: " + sum);
		System.out.println("TOTAL QUALITY POINTS: " + totalQualityPoints);
		System.out.println("NEW GPA: " + newGPA);

		calculateGPAForThisUser.setGPA(newGPA);
	}



	// could have a mode parameter to determine to calculate for grades
	// this is just calculating grades for undergraduates
	//private StringPlusCharacter[] generateAListOfNonRepeatedCourses()
	//{
	//	
	//}

	// ADMIN METHOD
	// ADDS THE USER INTO THE SYSTEM BY CampusID
	@SuppressWarnings("unchecked")
	public void addUserToSystem(User addThisUser) throws NullReferenceException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		userHolder = (ArrayList<User>) pm.getObjectById(userHolder);

		if(addThisUser != null)
		{
			// check if the user has a campusID yet
			// if not, then generate one
			String identification = addThisUser.getCampusID();

			// "" is the initial value set by the constructor
			if(identification == "")
				addThisUser.setCampusID(Integer.toString(lastGeneratedStudentID++));
			if(!userHolder.contains(addThisUser)) {
				userHolder.add(addThisUser);
				Collections.sort(userHolder);
				pm.makePersistent(userHolder);
				pm.close();
			}
		}	
	}
	
	
	
	public ArrayList<Course> getTheTeachingCoursesForTeacher(User theUser)
	{
		User returnThisTeachersTeachingCourses = null;
		ArrayList<Course> coursesTaughtByThisUser = null;
		
		int indexFound = binarySearchUserHolder(theUser);
		
		if(indexFound >= 0)
			returnThisTeachersTeachingCourses = userHolder.get(indexFound);
		
		if(returnThisTeachersTeachingCourses != null)
			coursesTaughtByThisUser = 
				   returnThisTeachersTeachingCourses.getTeachingTheseCourses();
		
		return coursesTaughtByThisUser;
	}
	
	
	
	public String displayTheStudentsNameInTheCourse(Course showThisCourse)
	{
		String studentNames = "";
		
		for(User theNames: showThisCourse.getStudentList())
			studentNames += theNames + "\n";
		
		return studentNames;
	}


	
	public User checkThePassword(String campusID, String password)
	{
		User returnThisUser = null;
		int indexFound = binarySearchUserHolder(campusID);
		boolean passwordMatched = false;
		
		if(indexFound >= 0)
		{	
			returnThisUser = userHolder.get(indexFound);
			passwordMatched = returnThisUser.getPassword().equals(password);
		}
		
		if(passwordMatched == false)
			returnThisUser = null;
		
		return returnThisUser;
	}
	
	
	
	// LFLFLFLFLFLFLFLFLFLFLFLFLFLLFLFLFLFLFLF
	private int binarySearchUserHolder(String campusID)
	{
		User findThisUser;
		int indexFound = -1;
		
		try
		{
			findThisUser = new User(campusID);
			indexFound = Collections.binarySearch(userHolder, findThisUser);
		}
		
		catch(NullReferenceException nre)
		{
			; // do nothing
		}
		
		return indexFound; 
	}
	
	
	
	// LFLFLFLFLFLFLFLFLFLFLFLFLFLLFLFLFLFLFLF
	private int binarySearchUserHolder(User findThisUser)
	{
		int indexFound = -1;
		
		indexFound = Collections.binarySearch(userHolder, findThisUser);
		
		return indexFound; 
	}


	// ADMIN METHOD
	// ADDS THE USER INTO THE SYSTEM BY CampusID
	@SuppressWarnings("unchecked")
	public void addCourseToSystem(Course addThisCourse) throws NullReferenceException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		courseHolder = (ArrayList<Course>) pm.getObjectById(courseHolder);

		if(addThisCourse != null)
		{
			// check if the course has a course ID
			// if not, then generate one
			String identification = addThisCourse.getCourseID();

			// "" is the initial value set by the constructor
			if(identification == "")
				addThisCourse.setCourseID(Integer.toString(lastGeneratedCourseID++));

			if(!courseHolder.contains(addThisCourse)) {
				courseHolder.add(addThisCourse);
				Collections.sort(courseHolder);
				pm.makePersistent(courseHolder);
				pm.close();
			}
		}	
	}

	public void removeUser(User toRemove) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		courseHolder = (ArrayList<Course>) pm.getObjectById(courseHolder);
		for(Course i : courseHolder) {
			switch(toRemove.getPermissionLevel()) {
			case STUDENT_PERMISSION_LEVEL : removeStudent(i,toRemove); break;
			case TEACHER_PERMISSION_LEVEL : removeTeacher(i,toRemove); break;
			}
		}
		pm.makePersistent(courseHolder);
		pm.close();
	}

	public void removeFromSystem(User toRemove) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		userHolder = (ArrayList<User>) pm.getObjectById(userHolder);		
		if(userHolder.contains(toRemove)) {
			removeUser(toRemove);
			userHolder.remove(toRemove);
		}
		pm.makePersistent(userHolder);
		pm.close();
	}

	private void removeStudent(Course course, User toRemove) {
		ArrayList<User> temp = course.getStudentList();
		if(temp.contains(toRemove)) {
			temp.remove(toRemove);
		}
	}

	private void removeTeacher(Course course, User toRemove) {
		if(toRemove.getTeachingTheseCourses().contains(course)) {
			toRemove.getTeachingTheseCourses().remove(course);
			try {
				course.setInstructorName("");
			} catch (NullReferenceException e) {
				;
			}
		}
	}

	// FLFLLFLFLFLFLFLFLLFLFLFLFLFLFLFLFLFL
	private int binarySearchCourseHolder(Course findThisCourse)
	{
		return Collections.binarySearch(courseHolder,findThisCourse);
	}

	/*
	private User getThisUser(int index)
	{
		User theUser = null;

		if(numberOfUsers >= 0 && numberOfUsers > index)
		    theUser = userHolder[index];

		return theUser;
	}
	 */


	public String changePermissionLevel(User theAdmin, User changeThisUser, 
			int newPermissionLevel) throws NotValidArgumentException
			{
		String returnedMessage = "";

		if(theAdmin.getPermissionLevel() == IT_ADMINISTRATOR_PERMISSION_LEVEL)
		{	
			changeThisUser.setPermissionLevel(newPermissionLevel);
			returnedMessage += changeThisUser.getName() + " had their " +
			"permission changed to " + 
			showTypeOfUser(changeThisUser);
		}

		return returnedMessage;
			}

	private String showTypeOfUser(User showThisUser)
	{
		String returnedString = "";

		if(showThisUser != null)
		{
			switch(showThisUser.getPermissionLevel())
			{
			// '0'
			case STUDENT_PERMISSION_LEVEL:
				returnedString += "Student";
				break;

				// '1'	
			case TEACHER_PERMISSION_LEVEL:
				returnedString += "Teacher";
				break;

				// '2'	
			case SCHOOL_ADMINISTRATOR_PERMISSION_LEVEL:
				returnedString += "School Administrator";
				break;

				// '3'
			case IT_ADMINISTRATOR_PERMISSION_LEVEL:
				returnedString += "IT Administrator";
				break;

				// could display student	
			default:
				returnedString += "NOT VALID";
				break;   	
			}
		}

		return returnedString;
	}

	// IT-LEVEL METHOD
	// NEED TO RESET PERMISSIONS TO EXCEED MAX CREDS AFTER SEMESTER
	public String giveStudentPermissionToExceedMaxCredits(User theStudent)
	{
		String returnedString = "";

		if(theStudent == null)
			returnedString += "Could not change the student's permission " +
			"level because he/she does not exist!\n";

		else
		{	
			theStudent.setHasPermissionToExceedMaxCredits(true);
			returnedString += theStudent.getName() + " now has permission " +
			"to exceed " + 
			MAX_NUMBER_OF_CREDITS_PER_SEMESTER +
			" credits this semester";
		}

		return returnedString;
	}



	public String addCourseList(User theUser, ArrayList<Course> listOfCourses) throws NotValidArgumentException, NullReferenceException
	{
		String listOfCourseMessages = "";

		if(theUser != null && listOfCourses != null)
			for(Course theCourse: listOfCourses)
				listOfCourseMessages += addUserToCourse(theUser, theCourse);


		return listOfCourseMessages;
	}

	// might want to check the lastAddDay
	private String addUserToCourse(User theUser, Course theCourse) throws NotValidArgumentException, NullReferenceException
	{
		String returnedString = "";

		if(theUser == null)
			returnedString += "Did not add the student because he/she does " +
			"not exist!\n";

		else if(theCourse == null)
			returnedString += "Did not add the course because it does " +
			"not exist!\n";

		else if(theUser.getPermissionLevel() == STUDENT_PERMISSION_LEVEL)
			returnedString += addStudentToCourse(theUser, theCourse);

		else if(theUser.getPermissionLevel() == TEACHER_PERMISSION_LEVEL)
			returnedString += addTeacherToCourse(theUser, theCourse);

		else if(theUser.getPermissionLevel() == 
			SCHOOL_ADMINISTRATOR_PERMISSION_LEVEL)
			returnedString += "Did not add " + theUser.getName() +
			" because he/she is a school administrator!\n";

		else if(theUser.getPermissionLevel() ==
			IT_ADMINISTRATOR_PERMISSION_LEVEL)
			returnedString += "Did not add " + theUser.getName() +
			" because he/she is an IT administrator!\n";

		return returnedString;
	}



	// could add an input list to reuse method
	private int findIfAnyStudentCoursesConflict(User theStudent, 
			Course theCourse)
	{
		int indexWhereThereIsAConflict = -1;


		if(theStudent != null)
		{	
			for(int i = 0; i < theStudent.getCurrentCoursesForStudent().size() 
			&& indexWhereThereIsAConflict == -1; i++)		
				if(theStudent.getCurrentCoursesForStudent().get(i)
						.getTheCourse().getTimeHeld()
						.doesTheTimesOverlap(theCourse.getTimeHeld()))
					indexWhereThereIsAConflict = i;
		}

		return indexWhereThereIsAConflict;
	}


	private int findIfAnyTeacherCoursesConflict(User theTeacher, 
			Course theCourse)
	{
		int indexWhereThereIsAConflict = -1;


		if(theTeacher != null)
		{	
			for(int i = 0; i < theTeacher.getTeachingTheseCourses().size() 
			&& indexWhereThereIsAConflict == -1; i++)		
				if(theTeacher.getTeachingTheseCourses().get(i)
						.getTimeHeld()
						.doesTheTimesOverlap(theCourse.getTimeHeld()))
					indexWhereThereIsAConflict = i;
		}

		return indexWhereThereIsAConflict;
	}





	private ArrayList<String> findListOfClassesThatDidNotMeetPrerequistes(
			User theUser, Course useThisCourse)
			{
		ArrayList<String> didNotTakeTheseClasses = new ArrayList<String>();

		for(int i = 0; i < 
		useThisCourse.getPrerequisitesNeededForThisCourse().size(); i++)
		{
			if(theUser.getCompletedCourses()
					.contains(useThisCourse
							.getPrerequisitesNeededForThisCourse().get(i)) == false)
			{
				didNotTakeTheseClasses.
				add(useThisCourse.getPrerequisitesNeededForThisCourse().get(i));
			}
		}

		return didNotTakeTheseClasses;

			}


	// COULD GENERATE A LIST AND WEED OUT SEARCH RESULTS WITH BIN SEARCH
	private boolean checkIfTheCourseWasAlreadyAdded(User theStudent, 
			Course theCourse)
	{
		boolean theCourseWasPreviouslyAdded = false;
		int compareToValue = 0;

		if(theStudent != null && theCourse != null)	
			for(int i = 0; i < theStudent.getCurrentCoursesForStudent().size() 
			&& theCourseWasPreviouslyAdded == false; i++)
			{
				compareToValue = 
					theStudent.getCurrentCoursesForStudent().get(i).
					getTheCourse().compareTo(theCourse);

				if(compareToValue == 0)
					theCourseWasPreviouslyAdded = true;
			}

		return theCourseWasPreviouslyAdded;
	}


	// admin override ability
	// add if the course was already added
	// add prerequisite checking
	// could add higher level course completed and deny
	private String addStudentToCourse(User addThisStudent, Course theCourse) throws NotValidArgumentException
	{
		String returnedMessage = "";
		int whereDoesTheConflictOccur =
			findIfAnyStudentCoursesConflict(addThisStudent, theCourse);

		boolean wasTheCourseAddedPreviously =
			checkIfTheCourseWasAlreadyAdded(addThisStudent, theCourse);

		/* LDLDLDLDLDLLDLDLDLDLDLD
		System.out.println("CONDITION #1: " + (theCourse.getStudentList().size() == theCourse.getCapacity()));
		System.out.println("CONDITION #2: " + (theCourse.getWaitList().size() < 
			                       MAX_NUMBER_OF_WAIT_LIST_SPOTS_FOR_A_COURSE));
		 */

		/*
		if(addThisStudent != null)
		{	
		    System.out.println("ADD THIS STUDENT: " + addThisStudent.getName());
		    System.out.println("WANTED CLASS: " + theCourse.getCourseName());
		    System.out.println("Num Credits for Student: " + addThisStudent.getNumberOfCreditsForThisSemester());
		    System.out.println("")

		    System.out.println("COND #1: " + ((addThisStudent.getNumberOfCreditsForThisSemester() + 
	                       theCourse.getCapacity()) > MAX_NUMBER_OF_CREDITS_PER_SEMESTER));
	        System.out.println("COND #2: " + ((addThisStudent.getHasPermissionToExceedMaxCredits() == false)));
		}
		 */

		// LDLDLDLDLDLLDLD
		System.out.println("WHERE DOES THE CONFLICT OCCUR: " + whereDoesTheConflictOccur);


		if(addThisStudent == null)
			returnedMessage += "Did not add the student becuase he/she does " +
			"not exist!\n";

		else if(addThisStudent.getPermissionLevel() != 
			STUDENT_PERMISSION_LEVEL)
			returnedMessage += "Did not add " + addThisStudent.getName() +
			" because this user is not a student!\n";

		else if((theCourse.getStudentList().size() == theCourse.getCapacity()) 
				&& (theCourse.getWaitList().size() < 
						MAX_NUMBER_OF_WAIT_LIST_SPOTS_FOR_A_COURSE))
		{ 
			returnedMessage += addThisStudent.getName() +
			" was added to the " + 
			theCourse.getCourseName() + "'s wait list!\n";

			addThisStudent.getWaitListedCourses().add(theCourse);
			theCourse.getWaitList().add(addThisStudent);
		}

		else if((theCourse.getStudentList().size() == theCourse.getCapacity()) 
				&& (theCourse.getWaitList().size() == 
					MAX_NUMBER_OF_WAIT_LIST_SPOTS_FOR_A_COURSE))
			returnedMessage += "Did not add " + addThisStudent.getName() +
			" because the class is full!\n";

		else if((addThisStudent.showNumberOfCreditsForThisSemester() + 
				theCourse.getNumberOfCredits()) > 
		MAX_NUMBER_OF_CREDITS_PER_SEMESTER &&
		addThisStudent.getHasPermissionToExceedMaxCredits() == 
			false)
			returnedMessage += "Did not add " + addThisStudent.getName() +
			" because the student does not have " +
			"permission to take over " +
			MAX_NUMBER_OF_CREDITS_PER_SEMESTER + " in " +
			"a semester!\n";

		else if(whereDoesTheConflictOccur >= 0)
			returnedMessage += "Did not add " + addThisStudent.getName() +
			" because the student's current courses " +
			"conflict with the attempted course!\n" +
			"[ " + addThisStudent
			.getCurrentCoursesForStudent()
			.get(whereDoesTheConflictOccur)
			.getTheCourse().getCourseName() + " (" +
			addThisStudent
			.getCurrentCoursesForStudent()
			.get(whereDoesTheConflictOccur)
			.getTheCourse().getTimeHeld()
			.showStartingToEndingTime() + ") ]\n";

		// there was not errors to stop the student from signing up for
		// a course
		else
		{
			try
			{
			    addThisStudent.getCurrentCoursesForStudent()
			    .add(new CoursePlusCharacter(theCourse, ' '));

			    theCourse.getStudentList().add(addThisStudent);

			    returnedMessage += addThisStudent.getName() + " was sucessfully " +
			    "added to " + theCourse.getCourseName() + "\n";
			}
			
			catch(NullReferenceException nre)
			{
				returnedMessage += nre.getMessage();
			}
		}


		return returnedMessage;
	}



	// add if the course was already added
	// add prerequisite checking
	// could add higher level course completed and deny
	private String addTeacherToCourse(User addThisTeacher, Course theCourse) throws NullReferenceException
	{
		String returnedMessage = "";
		int whereDoesTheConflictOccur =
			findIfAnyTeacherCoursesConflict(addThisTeacher, theCourse);
		boolean wasTheCourseAddedPreviously =
			checkIfTheCourseWasAlreadyAdded(addThisTeacher, theCourse);

		// LDLDLDLDLDLLDLD
		System.out.println("WHERE DOES THE CONFLICT OCCUR: " + whereDoesTheConflictOccur);


		if(addThisTeacher == null)
			returnedMessage += "Did not add the teacher becuase he/she does " +
			"not exist!\n";

		else if(whereDoesTheConflictOccur >= 0)
			returnedMessage += "Did not add " + addThisTeacher.getName() +
			" to be the instructor because this course " +
			"conflicted! [" +
			addThisTeacher.getTeachingTheseCourses()
			.get(whereDoesTheConflictOccur).getCourseName() +
			" (" +
			addThisTeacher.getTeachingTheseCourses()
			.get(whereDoesTheConflictOccur).getTimeHeld()
			.showStartingToEndingTime() + ") ]\n";

		else
		{
			addThisTeacher.getTeachingTheseCourses().add(theCourse);

			theCourse.setInstructorName(addThisTeacher.getName());

			returnedMessage += addThisTeacher.getName() + " was sucessfully " +
			"added to " + theCourse.getCourseName() + "\n";
		}


		return returnedMessage;
	}


	// FLFLFLFLLFLFLFLFLFLFLFLF
	public String toString()
	{
		String returnThisString = "";

		for(int i = 0; i < userHolder.size(); i++)
			returnThisString += userHolder.get(i) + "\n";

		for(int i = 0; i < courseHolder.size(); i++)
			returnThisString += courseHolder.get(i) + "\n";

		return returnThisString;
	}


	/*
	public void moveCurrentCoursesToCompleted()
	{
		int i = 0;

		if(completedCourses.length < 
				(numberOfCurrentCoursesForStudent + numberOfCompletedCourses))
				increaseSizeOfCompletedCourses();


		while(currentCoursesForStudent[i] != null)
		{
			completedCourses[numberOfCompletedCourses++] =
				        new StringPlusCharacter(currentCoursesForStudent[i]);

			i++;
		}
	}
	 */

	// admin override ability
	public String removeCourse(User theUser, Course theCourse)
	{
		String returnedString = "";

		if(theUser != null && theCourse != null)
		{
			if(theUser.getPermissionLevel() == STUDENT_PERMISSION_LEVEL)
				returnedString += ""; //removeCourseFromStudent(theUser, theCourse);

			else if(theUser.getPermissionLevel() == TEACHER_PERMISSION_LEVEL)
				returnedString += ""; //removeCourseFromTeacher(theUser, theCourse);

			else if(theUser.getPermissionLevel() == 
				SCHOOL_ADMINISTRATOR_PERMISSION_LEVEL ||
				theUser.getPermissionLevel() ==
					IT_ADMINISTRATOR_PERMISSION_LEVEL)
				returnedString += "Did not remove " + theCourse.getCourseName() +
				"because the user is administrator!\n";
		}

		return returnedString;
	}


	// ADMIN method
	public String changeLastDayToDropDate(int month, int dayNumber, int year)
	{
		String returnedString = "";
		String isTheInputValid = "";

		try
		{
			isTheInputValid =
				MonthDayYear.checkIfTheCalendarDateIsValid(month, dayNumber, year);

			// the check method should return an empty string if there was no problems 
			if(isTheInputValid.equals(""))
			{
				/*
		    	System.out.println("777777777777777777777777777");
			    System.out.println("MONTH: " + month);
			    System.out.println("DAY: " + dayNumber);
			    System.out.println("YEAR: " + year);
			    System.out.println(showLastDayToDrop());
				 */

				finalDayToDrop.setAllThreeFields(month, dayNumber, year);

				/*
			    System.out.println(showLastDayToDrop());
			    System.out.println("777777777777777777777777777");
				 */

				returnedString += "The final day to DROP was changed to " + 
				finalDayToDrop + "\n";
			} // end of if statement

			else
				returnedString += "The final day to DROP was NOT changed " +
				"because " + isTheInputValid + "\n";
		} // end of try block

		catch(NotValidArgumentException nvae)
		{
			returnedString += nvae.getMessage();
		}

		return returnedString;
	}


	// ADMIN method
	public String changeLastDayToAddDate(int month, int dayNumber, int year)
	{
		String returnedString = "";

		try
		{
			String isTheInputValid = 
				MonthDayYear.checkIfTheCalendarDateIsValid(month, dayNumber, year);

			// the check method should return an empty string if there was no
			// problems 
			if(isTheInputValid.equals(""))
			{
				finalDayToAdd.setAllThreeFields(month, dayNumber, year);
				returnedString += "The final day to ADD was changed to " + 
				finalDayToAdd + "\n";
			} // end of if statement

			else
				returnedString += "The final day to ADD was NOT changed " +
				"because " + isTheInputValid + "\n";
		} // end of try block

		catch(NotValidArgumentException nvae)
		{
			returnedString += nvae.getMessage();
		}

		return returnedString;
	}




	//public String change




	// remove the boolean parameter
	/*
	private boolean removeCourseFromStudent(User theUser, Course theCourse) //, 
			                                    //boolean didTheWithdrawDatePass)
	{
		int locationFound = theUser.getCurrentCoursesForStudent().indexOf(theCourse);

		if(locationFound >= 0 && theUser.getPermissionLevel() == STUDENT_PERMISSION_LEVEL)
		{
			StringPlusCharacter[] courseList = 
				                         theUser.getCurrentCoursesForStudent();
			int numberOfCourses = theUser.getNumberOfCurrentCoursesForStudent();

			// setting the grade for the course to be 'W'
			if(didTheWithdrawDatePass == true)
				courseList[locationFound].setTheChar('W');


			else
			{	
			    shiftCoursesOver(theUser, locationFound);
			    theUser.setNumberOfCurrentCoursesForStudent(
			    		                                  numberOfCourses - 1);
			}
		}

		else if(locationFound >= 0 
				   && theUser.getPermissionLevel() == TEACHER_PERMISSION_LEVEL)
		{
			int numberOfCourses = theUser.getNumberOfCurrentCoursesTaught();

			shiftCoursesOver(theUser, locationFound);
			theUser.setNumberOfCurrentCoursesTaught(numberOfCourses - 1);
		}

		return (locationFound >= 0);
	}



	// RETURN TYPE AND PARAMETER AS AN ARRAYLIST?
	// I FEEL THAT AN ARRAYLIST WILL BE HELPFUL
	// remove the boolean parameter
	public String dropCourse(User theUser, String[] listOfCourses, 
			                                        boolean passedWithdrawDate)
	{
		String listOfCoursesNotRemoved = "";
		boolean wasTheCourseRemoved = false;

		for(String theCourse: listOfCourses)
		{
			wasTheCourseRemoved = removeCourse(theUser, theCourse, 
					                                       passedWithdrawDate);

			if(wasTheCourseRemoved == false)
				listOfCoursesNotRemoved += theCourse + " ";
		}

		return listOfCoursesNotRemoved;
	}
	 */



	public String showUserInformation(User theUser)
	{
		String userInfoString = "";
		// String.format(format, args)
		// do I need to run calculateGPA method before calling this method
		// CURRENT COURSES NEEDS 18 to 20 SPACES

		if(theUser == null)
			userInfoString += "Can not the user's information because " +
			"does not exist!\n";

		else if(theUser.getPermissionLevel() == STUDENT_PERMISSION_LEVEL)
			userInfoString += theUser.showStudentInfo() + "\n\n";

		else if(theUser.getPermissionLevel() == TEACHER_PERMISSION_LEVEL)
			userInfoString += theUser.showTeacherInfo() + "\n\n";

		else if(theUser.getPermissionLevel() == 
			SCHOOL_ADMINISTRATOR_PERMISSION_LEVEL ||
			theUser.getPermissionLevel() == 
				IT_ADMINISTRATOR_PERMISSION_LEVEL)
			userInfoString += theUser.showAdminInfo();

		return userInfoString;
	}



	public String showTeacherCourses(User theTeacher)
	{
		String returnedString = "";

		if(theTeacher.getPermissionLevel() == TEACHER_PERMISSION_LEVEL)
			returnedString += theTeacher.showCurrentCoursesTaught() + "\n";

		else
			returnedString += theTeacher.getName() + " is not an instructor, " +
			"so this user is not teaching any courses!\n";

		return returnedString;
	}


	public String showLastDayToDrop()
	{
		return finalDayToDrop.toString() + "\n";
	}

	public String showLastDayToAdd()
	{
		return finalDayToAdd.toString() + "\n";
	}

	//////////////////////////////////////////////////////////////////////////
	public String showCourseList()
	{
		return courseHolder.toString();
	}


	public String showUserList()
	{
		return userHolder.toString();
	}



	// drop = CHECK WAIT LIST
	public static void main(String[] args) throws NullReferenceException, NotValidArgumentException
	{
		OdinsFistSystem ofs = new OdinsFistSystem();
		User nullUserReference = null;

		// creating users and setting field
		User abc = new User();
		abc.setName("David");
		//abc.setCampusID("00001");

		User def = new User();
		def.setName("Nick");
		//def.setCampusID("00002");

		User ghi = new User();
		ghi.setName("Jasmine");
		//ghi.setCampusID("00003");

		User jkl = new User();
		jkl.setName("Leandro");
		//jkl.setCampusID("00004");

		ofs.addUserToSystem(def);
		ofs.addUserToSystem(abc);
		ofs.addUserToSystem(jkl);
		ofs.addUserToSystem(ghi);
		ofs.addUserToSystem(abc);

		// creating classes for the student
		Course classA = new Course();
		classA.setCourseName("A");
		Course classB = new Course();
		classB.setCourseName("B");
		Course classC = new Course();
		classC.setCourseName("C");
		Course classD = new Course();
		classD.setCourseName("D");

		// adding courses
		ofs.addCourseToSystem(classB);
		ofs.addCourseToSystem(classD);
		ofs.addCourseToSystem(classC);
		ofs.addCourseToSystem(classA);


		// checking the items stored in the course list
		System.out.println(ofs);

		System.out.println("TESTING THE ADDING METHODS");
		System.out.println("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV");

		// testing the addStudentToCourse()
		// trying to get the null message
		System.out.println(ofs.addStudentToCourse(nullUserReference, classA));


		// changing the user to be a different type of user
		abc.setPermissionLevel(3);

		// testing the addStudentToCourse()
		// trying to get the not student message
		System.out.println(ofs.addStudentToCourse(abc, classA));


		// changing the User back as a student
		abc.setPermissionLevel(0);

		// testing adding to a wait list by change the capacity of the course
		classA.setCapacity(1);

		System.out.println("CHECKING THE CAPACITY OF CLASS A: " + 
				classA.getCapacity());

		// def should be added to the wait list
		System.out.println(ofs.addStudentToCourse(abc, classA));
		System.out.println(ofs.addStudentToCourse(def, classA));

		// printing the system's state
		System.out.println(ofs);

		// adding another student to classA, it should result in a
		// can not add student name because the class is full
		// WORKS WHEN THE NUMBER OF WAIT LIST SPOTS WAS CHANGED TO ONE
		//System.out.println(ofs.addStudentToCourse(ghi, classA));

		// trying to get the max number of credits message
		//abc.setNumberOfCreditsForThisSemester(19);
		classD.setCapacity(5);
		classD.setNumberOfCredits(3);
		System.out.println(ofs.addStudentToCourse(abc, classD));

		// trying to get the conflict time message
		classC.setCapacity(5);
		System.out.println("NUMBER OF CREDS FOR DAVID: " + 
				abc.showNumberOfCreditsForThisSemester());
		System.out.println("NUMBER OF CREDS FOR CLASS C: " + 
				classC.getNumberOfCredits());
		System.out.println(ofs.addStudentToCourse(abc, classC));


		/*
		// print out the list of courses and testing the binary search (WORKS)
		System.out.println("########################################################");
		System.out.println(ofs.showCourseList());
		System.out.println("Location of classA: " + ofs.binarySearchCourseHolder(classA));
		System.out.println("Location of classB: " + ofs.binarySearchCourseHolder(classB));
		System.out.println("Location of classC: " + ofs.binarySearchCourseHolder(classC));
		System.out.println("Location of classD: " + ofs.binarySearchCourseHolder(classD));

		// print out the list of students and testing the binary search (WORKS)
		System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		System.out.println(ofs.showUserList());
		System.out.println("Location of David: " + ofs.binarySearchUserHolder(abc));
		System.out.println("Location of Nick: " + ofs.binarySearchUserHolder(def));
		System.out.println("Location of Jasmine: " + ofs.binarySearchUserHolder(ghi));
		System.out.println("Location of Leandro: " + ofs.binarySearchUserHolder(jkl));
		 */


		// Testing calculateGPA method (WORKS)
		ArrayList<CoursePlusCharacter> cpc = new ArrayList<CoursePlusCharacter>();
		classA.setNumberOfCredits(4);
		classB.setNumberOfCredits(3);
		cpc.add(new CoursePlusCharacter(classA, 'A'));
		cpc.add(new CoursePlusCharacter(classB, 'B'));
		abc.setCompletedCourses(cpc);
		ofs.calculateGPA(abc);
		System.out.println(abc.getGPA());


		System.out.println("*******************************************************");
		// Testing teacher methods
		User teacherA = new User();
		User teacherB = new User();
		User teacherC = new User();
		User teacherD = new User();


		// changing the users to become teachers
		teacherA.setPermissionLevel(TEACHER_PERMISSION_LEVEL);
		teacherB.setPermissionLevel(TEACHER_PERMISSION_LEVEL);
		teacherC.setPermissionLevel(TEACHER_PERMISSION_LEVEL);
		teacherD.setPermissionLevel(TEACHER_PERMISSION_LEVEL);

		// adding names to the teacher
		teacherA.setName("PROF A");
		teacherB.setName("PROF B");
		teacherC.setName("PROF C");
		teacherD.setName("PROF D");

		teacherA.setPassword("Jelly JAM");

		// trying the new addUserToCourseMethod
		System.out.println(ofs.addUserToCourse(teacherA, classA));
		// should be denied
		System.out.println(ofs.addUserToCourse(teacherA, classB));

		System.out.println(ofs.showCourseList());

		// testing password check method
		// should return false
		System.out.println(ofs.checkIfTheEnteredPasswordIsValid(teacherA, "Jelly Jam"));
		// should return true
		System.out.println(ofs.checkIfTheEnteredPasswordIsValid(teacherA, "Jelly JAM"));
		// adding another course to teacherA
		//classB.setTimeHeld(new Time(1000, 1200, false));
		// print out the instructor's courses


		// testing the changeLastdayTo.... methods
		// month = 0 -> January
		System.out.println(ofs.changeLastDayToDropDate(1, 29, 2010));
		System.out.println(ofs.showLastDayToDrop());
	}	
}

//TODO implement add student from wait list for teacher (takes in student and course)
//TODO make a method for teacher to assign grades to students in a course
//TODO search student/teacher/admin records
//TODO check for if a teacher is already teaching a course
//TODO make list of user generated admin-requests (admin request class?)
//TODO calendar restrictions
//TODO restrict access to a class (open or closed class)
//TODO restrict student ability to register for a class (prerequisite or more than 3 times)